﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Lacrima.Game
{
    public partial class Snake : Form
    {
        /// <summary>
        /// 单位长度
        /// </summary>
        private const int unitLength = 15;

        /// <summary>
        /// 贪吃蛇最大长度
        /// </summary>
        public const int SnakeMaxLength = 500;

        /// <summary>
        /// 缓存食物的坐标
        /// </summary>
        public Point FoodLocation = new Point();
        public Point[] snakeArray = new Point[SnakeMaxLength];

        /// <summary>
        /// 贪吃蛇的长度
        /// </summary>
        public int snakeLength = 10;

        public Keys keyDirection = Keys.Right;
        public bool panDuan = true;

        public Snake()
        {
            InitializeComponent();
            this.snakeTimer.Enabled = true;
            this.snakeTimer.Interval = 200;
            this.snakeTimer.Tick += new System.EventHandler(this.snakeTimer_Tick);

            int temp = 0;
            for (int i = snakeLength - 1; i >= 0; i--)
            {
                snakeArray[i].X = temp;
                snakeArray[i].Y = 0;
                temp += unitLength;
            }
        }

        /// <summary>
        /// 画一个食物
        /// </summary>
        public void DrawFood(int x, int y)
        {
            Graphics g = this.CreateGraphics();
            Pen pen = new Pen(Color.Red, 2);
            SolidBrush brush = new SolidBrush(Color.Green);
            g.DrawRectangle(pen, x, y, unitLength, unitLength);
            g.FillRectangle(brush, x, y, unitLength, unitLength);
        }

        /// <summary>
        /// 设置Point数组坐标
        /// </summary>
        public void Forward()
        {
            for (int i = snakeLength - 1; i > 0; i--)
            {
                snakeArray[i].X = snakeArray[i - 1].X;
                snakeArray[i].Y = snakeArray[i - 1].Y;
            }

            snakeArray[0].X += unitLength * this.GetHorizontalDirection(this.keyDirection);
            snakeArray[0].Y += unitLength * this.GetVerticalDirection(this.keyDirection);
        }

        /// <summary>
        /// 时间事件
        /// </summary>
        private void snakeTimer_Tick(object sender, EventArgs e)
        {
            // 贪吃蛇前进事件，使蛇向前移动
            Forward();

            Graphics g = this.CreateGraphics();
            //清除整个画面
            g.Clear(Color.DarkKhaki);

            this.DrawSnake();

            if (panDuan)
            {
                ShowFood();
                //DrawFood(FoodLct.X, FoodLct.Y);
                panDuan = false;
            }

            if (EatedFoot(FoodLocation))
            {
                ShowFood();
                DrawFood(FoodLocation.X, FoodLocation.Y);
            }
            else
            {
                DrawFood(FoodLocation.X, FoodLocation.Y);
            }

            if (CheckSnakeHeadInSnakeBody() || CheckSnakeBodyInFrm())
            {
                this.snakeTimer.Enabled = false;
                MessageBox.Show("游戏结束！");
            }
        }

        /// <summary>
        /// 按下方向键
        /// </summary>
        private void Snake_KeyDown(object sender, KeyEventArgs e)
        {
            keyDirection = e.KeyCode;
        }

        /// <summary>
        /// 判断是否撞到自己
        /// </summary>
        public bool CheckSnakeHeadInSnakeBody()
        {
            return this.CheckInSnakeBody(this.snakeArray[0].X, this.snakeArray[0].Y, 1);
        }
        /// <summary>
        /// 检查输入的坐标是否在蛇的身上
        /// </summary>
        public bool CheckInSnakeBody(int x, int y, int snkHead)
        {
            for (int i = snkHead; i < snakeLength; i++)
            {
                if (x == this.snakeArray[i].X && y == this.snakeArray[i].Y)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 判断是否撞墙
        /// </summary>
        /// <returns></returns>
        public bool CheckSnakeBodyInFrm()
        {
            if (this.snakeArray[0].X >= 594 || this.snakeArray[0].Y >= 399 - 32 || this.snakeArray[0].X < 0 || this.snakeArray[0].Y < 0)
                return true;
            else
                return false;
        }

        /// <summary>
        /// 随机显示食物
        /// </summary>
        public void ShowFood()
        {
            // 修改：仇士龙，2017年6月3日19:13:34，修正坐标超出窗体范围的Bug
            ResetPosition();
            while (!this.IsValidPosition(FoodLocation.X, FoodLocation.Y))
            {
                ResetPosition();
            }
        }

        /// <summary>
        /// 判断是否吃到食物
        /// </summary>
        public bool EatedFoot(Point FoodLct)
        {
            if (snakeArray[0].X == FoodLct.X && snakeArray[0].Y == FoodLct.Y)
            {
                if (snakeLength < SnakeMaxLength)
                {
                    snakeLength += 1;
                    snakeArray[snakeLength].X = snakeArray[snakeLength - 1].X;
                    snakeArray[snakeLength].Y = snakeArray[snakeLength - 1].Y;
                }
                return true;
            }
            else
                return false;
        }

        /// <summary>
        /// 新增：仇士龙，2017年6月3日19:12:16
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private bool IsValidPosition(int x, int y)
        {
            // 350为纵向最大值
            return x > 0 && x < 525 && y > 0 && y < 350;
        }

        /// <summary>
        /// 新增:仇士龙，2017年6月3日19:12:26
        /// </summary>
        private void ResetPosition()
        {
            Random rmd = new Random();
            FoodLocation.X = rmd.Next(0, this.Width / unitLength) * unitLength;
            FoodLocation.Y = rmd.Next(0, this.Height / unitLength) * unitLength;
        }

        private int GetVerticalDirection(Keys keyDirection)
        {
            if (keyDirection == Keys.Down)
            {
                return 1;
            }
            else if (keyDirection == Keys.Up)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        private int GetHorizontalDirection(Keys keyDirection)
        {
            if (keyDirection == Keys.Right)
            {
                return 1;
            }
            else if (keyDirection == Keys.Left)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        private void DrawSnake()
        {
            Graphics graphics = this.CreateGraphics();
            Pen pen = new Pen(Color.Blue, 2);
            for (int i = 0; i < snakeLength; i++)
            {
                graphics.DrawRectangle(pen, snakeArray[i].X, snakeArray[i].Y, unitLength, unitLength);
                graphics.FillRectangle(Brushes.Green, snakeArray[i].X, snakeArray[i].Y, unitLength, unitLength);
            }
        }

        /// <summary>
        /// 设置双缓冲，解决画面闪的问题
        /// http://blog.csdn.net/acs713/article/details/16359551
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Snake_Load(object sender, EventArgs e)
        {
            this.DoubleBuffered = true;
        }
    }
}
